package com.life.ai.server.modules.develop.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.JvmInfo;
import cn.hutool.system.OsInfo;
import cn.hutool.system.RuntimeInfo;
import cn.hutool.system.SystemUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.life.ai.server.common.domain.R;
import com.life.ai.server.common.utils.NetWorkInfoUtil;
import com.life.ai.server.modules.develop.entity.ServerMonitorVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.FileSystem;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
 * ServerMonitorController
 *
 * @author kylewka
 * @since 2024/5/6
 */
@Api(tags = "服务监控-接口列表")
@RestController
@RequestMapping("/develop/monitor")
public class ServerMonitorController {

    @ApiOperationSupport(order = 1)
    @ApiOperation("获取服务器监控信息")
    @GetMapping("/serverInfo")
    public R<ServerMonitorVo> serverInfo() {
        return R.ok(localServerInfo());
    }

    /**
     * 获取本机服务信息
     */
    private ServerMonitorVo localServerInfo(){
        ServerMonitorVo devMonitorServerResult = new ServerMonitorVo();
        SystemInfo si = new SystemInfo();
        HardwareAbstractionLayer hal = si.getHardware();
        CentralProcessor cpu = hal.getProcessor();

        // CPU信息
        ServerMonitorVo.ServerCpuInfo serverCpuInfo = new ServerMonitorVo.ServerCpuInfo();
        serverCpuInfo.setCupName(StrUtil.trim(cpu.getProcessorIdentifier().getName()));
        serverCpuInfo.setCupNum(cpu.getPhysicalPackageCount() + "颗物理CPU");
        serverCpuInfo.setCpuPhysicalCoreNum(cpu.getPhysicalProcessorCount() + "个物理核心");
        serverCpuInfo.setCpuLogicalCoreNum(cpu.getLogicalProcessorCount() + "个逻辑核心");
        long[] prevTicks = cpu.getSystemCpuLoadTicks();
        Util.sleep(500);
        long[] ticks = cpu.getSystemCpuLoadTicks();
        long nice = ticks[CentralProcessor.TickType.NICE.getIndex()]
                - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
        long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()]
                - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
        long softIrq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()]
                - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
        long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()]
                - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
        long sys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()]
                - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
        long user = ticks[CentralProcessor.TickType.USER.getIndex()]
                - prevTicks[CentralProcessor.TickType.USER.getIndex()];
        long ioWait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()]
                - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
        long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()]
                - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
        long totalCpu = user + nice + sys + idle + ioWait + irq + softIrq + steal;
        serverCpuInfo.setCpuSysUseRate(NumberUtil.div(NumberUtil.mul(sys, 100), totalCpu, 2) + "%");
        serverCpuInfo.setCpuUserUseRate(NumberUtil.div(NumberUtil.mul(user, 100), totalCpu, 2) + "%");
        serverCpuInfo.setCpuTotalUseRate(NumberUtil.div(NumberUtil.mul(NumberUtil.add(sys, user), 100), totalCpu, 2));
        serverCpuInfo.setCpuWaitRate(NumberUtil.div(NumberUtil.mul(ioWait, 100), totalCpu, 2) + "%");
        serverCpuInfo.setCpuFreeRate(NumberUtil.div(NumberUtil.mul(idle, 100), totalCpu, 2) + "%");
        devMonitorServerResult.setServerCpuInfo(serverCpuInfo);

        // 内存信息
        GlobalMemory memory = hal.getMemory();
        ServerMonitorVo.ServerMemoryInfo serverMemoryInfo = new ServerMonitorVo.ServerMemoryInfo();
        long used = memory.getTotal() - memory.getAvailable();
        serverMemoryInfo.setMemoryTotal(FileUtil.readableFileSize(memory.getTotal()));
        serverMemoryInfo.setMemoryUsed(FileUtil.readableFileSize(used));
        serverMemoryInfo.setMemoryFree(FileUtil.readableFileSize(memory.getAvailable()));
        serverMemoryInfo.setMemoryUseRate(NumberUtil.mul(NumberUtil.div(used, memory.getTotal(), 4), 100));
        devMonitorServerResult.setServerMemoryInfo(serverMemoryInfo);

        // 存储信息
        ServerMonitorVo.ServerStorageInfo serverStorageInfo = new ServerMonitorVo.ServerStorageInfo();
        OperatingSystem operatingSystem = si.getOperatingSystem();
        FileSystem fileSystem = operatingSystem.getFileSystem();
        AtomicLong storageTotal = new AtomicLong();
        AtomicLong storageUsed = new AtomicLong();
        AtomicLong storageFree = new AtomicLong();
        fileSystem.getFileStores().forEach(osFileStore -> {
            long totalSpace = osFileStore.getTotalSpace();
            long usableSpace = osFileStore.getUsableSpace();
            long freeSpace = osFileStore.getFreeSpace();
            long usedSpace = totalSpace - usableSpace;
            storageTotal.addAndGet(totalSpace);
            storageUsed.addAndGet(usedSpace);
            storageFree.addAndGet(freeSpace);
        });
        serverStorageInfo.setStorageTotal(FileUtil.readableFileSize(storageTotal.get()));
        serverStorageInfo.setStorageUsed(FileUtil.readableFileSize(storageUsed.get()));
        serverStorageInfo.setStorageFree(FileUtil.readableFileSize(storageFree.get()));
        serverStorageInfo.setStorageUseRate(NumberUtil.mul(NumberUtil.div(storageUsed.doubleValue(), storageTotal.doubleValue(), 4), 100));
        devMonitorServerResult.setServerStorageInfo(serverStorageInfo);

        // 网络信息
        ServerMonitorVo.ServerNetworkInfo serverNetworkInfo = new ServerMonitorVo.ServerNetworkInfo();
        Map<String, String> networkUpRate = NetWorkInfoUtil.getNetworkUpRate();
        serverNetworkInfo.setUpLinkRate(networkUpRate.get("UP"));
        serverNetworkInfo.setDownLinkRate(networkUpRate.get("DOWN"));
        devMonitorServerResult.setServerNetworkInfo(serverNetworkInfo);

        // 服务器信息
        OsInfo osInfo = SystemUtil.getOsInfo();
        ServerMonitorVo.ServerBaseInfo serverBaseInfo = new ServerMonitorVo.ServerBaseInfo();
        serverBaseInfo.setServerName(NetUtil.getLocalHostName());
        serverBaseInfo.setServerOs(osInfo.getName());
        serverBaseInfo.setServerIp(NetUtil.getLocalhostStr());
        serverBaseInfo.setServerArchitecture(osInfo.getArch());
        devMonitorServerResult.setServerBaseInfo(serverBaseInfo);

        // JVM信息
        ServerMonitorVo.ServerJvmInfo serverJvmInfo = new ServerMonitorVo.ServerJvmInfo();
        RuntimeInfo runtimeInfo = SystemUtil.getRuntimeInfo();
        JvmInfo jvmInfo = SystemUtil.getJvmInfo();
        serverJvmInfo.setJvmName(jvmInfo.getName());
        serverJvmInfo.setJvmVersion(jvmInfo.getVersion());
        long totalMemory = runtimeInfo.getTotalMemory();
        serverJvmInfo.setJvmMemoryTotal(FileUtil.readableFileSize(totalMemory));
        serverJvmInfo.setJvmMemoryFree(FileUtil.readableFileSize(runtimeInfo.getFreeMemory()));
        long jvmMemoryUsed = NumberUtil.sub(new BigDecimal(runtimeInfo
                .getTotalMemory()), new BigDecimal(runtimeInfo.getFreeMemory())).longValue();
        serverJvmInfo.setJvmMemoryUsed(FileUtil.readableFileSize(jvmMemoryUsed));
        double jvmUseRate = NumberUtil.mul(NumberUtil.div(jvmMemoryUsed, totalMemory, 4), 100);
        serverJvmInfo.setJvmUseRate(jvmUseRate);
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        DateTime startTime = DateUtil.date(runtimeMXBean.getStartTime());
        serverJvmInfo.setJvmStartTime(DateUtil.formatDateTime(startTime));
        serverJvmInfo.setJvmRunTime(DateUtil.formatBetween(startTime, DateTime.now()));
        serverJvmInfo.setJavaVersion(SystemUtil.get("java.version", false));
        serverJvmInfo.setJavaPath(SystemUtil.get("java.home", false));
        devMonitorServerResult.setServerJvmInfo(serverJvmInfo);
        return devMonitorServerResult;
    }
}
